package com.weiaibenpao.demo.chislim.service;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.model.LatLng;
import com.orhanobut.logger.Logger;
import com.weiaibenpao.demo.chislim.BuildConfig;
import com.weiaibenpao.demo.chislim.MyApplication;
import com.weiaibenpao.demo.chislim.R;
import com.weiaibenpao.demo.chislim.db.entities.RunningRecord;
import com.weiaibenpao.demo.chislim.db.preferences.RunningPreferences;
import com.weiaibenpao.demo.chislim.tts.util.SpeechUtil;
import com.weiaibenpao.demo.chislim.utils.RunningUtils;

import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;

import io.objectbox.Box;
import weiaibenpao.com.library.pedometer.ApplicationModule;
import weiaibenpao.com.library.pedometer.bean.PedometerCardEntity;
import weiaibenpao.com.library.pedometer.presenter.PedometerPresenter;
import weiaibenpao.com.library.pedometer.view.IPedometerView;



/**
 * Created by ZJL on 2017/8/1.
 * 注意：定位会造成内存规律性升降（升幅不大），不过整体平稳,这是正常现象
 */

public class RunningService extends Service implements AMapLocationListener, IPedometerView {
    private static final String ACTION_KEEP_ALIVE = "RunningService.Action.KeepAlive";
    private static final String TAG = "RunningService";
    private static final int KEEP_ALIVE_INTERVAL = BuildConfig.DEBUG ? 3 * 1000 : 5 * 1000;
    private static final int LOCATION_INTERVAL = 5000;
    private static final int MAX_LOCATION_CALLBACK_INTERVAL = 5 * LOCATION_INTERVAL;
    private static final int DEFAULT_WEIGHT = 65;//kg
    private static final int DEFAULT_HEIGHT = 170;//cm
    private static final int FILTER_THRESHOLD = 30;
    private static final int HUMAN_RUNNING_VELOCITY_UPPER_LIMIT = 12;//m/s
    public static final int RUNNING = 1;
    public static final int PAUSE = 2;
    public static final int FINISH = 3;
    public static final String NEED_SAVE_STATE = "need_save_state";
    public static final String NEED_SAVE_RECORD = "need_save_record";
    public static final String NEED_EXTRA_DATA = "need_extra_data";
    public static final String IS_INDOOR_RUNNING = "is_indoor_running";
    public static final String USER_HEIGHT = "user_height";
    public static final String USER_WEIGHT = "user_weight";
    public static final String RUNNING_ACTIVITY = "running_activity";
    public static final String LAT_LNG = "lat_lng";
    public static final String KM_LAT_LNG = "km_lat_lng";//整公里点
    public static final String CALORIE = "calorie";
    public static final String DISTANCE = "runningDistance";
    public static final String PACE = "pace";      //实时配速
    public static final String KM_PACE = "km_pace";//整公里配速
    public static final String KM_VALUE = "km_value";//整公里配速对应的整公里数
    public static final String STEP = "step";
    public static final String ALTITUDE = "altitude";
    public static final String STRIDE = "stride";
    public static final String FREQUENCY = "frequency";
    public static final String SPEED = "speed";

    private AMapLocationClient mLocationClient = null;
    private OnDataUpdatedListener mOnDataUpdateListener;
    private Timer mTimer = new Timer();
    private LatLng lastLatLng;
    private long runningStartTime;               //开始跑步的时间戳，如果从暂停到恢复跑步，那么重新获取时间戳，因为跑步时间是按段来累计，一个起始到暂停就是一段
    private long runningTimeSum;                 //开始跑到暂停算一段，每跑一段累加一次  （单位毫秒）
    private int stepIncrement;
    private int stepCountSum;                    //步数累计总数
    private int mRunningState;
    private int stepCount = 0;
    private float runningDistance;                    //单位 米
    private float lastKmDistance;
    private int lastKmRunningTime;
    private float lastCalculateDistance;
    private int lastCalculateRunningTime;
    private int lastCalculateStepCount;
    private long lastLocationCallbackTime;
    private int mUserHeight;
    private float mUserWeight;
    private boolean mIsBound;
    private boolean mIsResourceReleased;
    private boolean mIsTimerSet;
    private boolean mNeedSaveRecord;          //是否需要保存运动记录
    private boolean mNeedExtraData;          //是否需要除五大显示数据的额外的数据
    private boolean mNeedSaveState;          //是否需要保存状态，如果需要保存状态那么RunningService和跑步界面就需要恢复状态
    private boolean mIsIndoorRunning;        //是否是室内跑，室内跑无需开启定位
    private DecimalFormat mDecimalFormat = new DecimalFormat("0.00");
    private Box<RunningRecord> mRunningRecordBox;
    private Handler mHandler = new Handler(Looper.getMainLooper());


    @Override
    public void onCreate() {
        super.onCreate();
        mRunningRecordBox = MyApplication.getInstance().getBoxStore().boxFor(RunningRecord.class);
        initLocation();
        initPedometer();
        Log.e(TAG, "onCreate " + this);
        int runningState = RunningPreferences.getInstance().getRunningState();
        if (runningState == RUNNING || runningState == PAUSE) { //如果有未结束的跑步，那么恢复状态
            restoreRunning(runningState);
        }
    }

    private void restoreRunning(int runningState) {
        mIsIndoorRunning = RunningPreferences.getInstance().getBoolean(IS_INDOOR_RUNNING);
        runningTimeSum = RunningPreferences.getInstance().getRunningTime() * 1000;
        runningDistance = RunningPreferences.getInstance().getRunningDistance();
        stepCountSum = RunningPreferences.getInstance().getRunningStep();
        stepCount = stepCountSum;
        lastCalculateDistance = RunningPreferences.getInstance().getLastCalculateDistance();
        lastKmDistance = RunningPreferences.getInstance().getLastKmDistance();
        lastCalculateRunningTime = RunningPreferences.getInstance().getLastCalculateRunningTime();
        lastKmRunningTime = RunningPreferences.getInstance().getLastKmRunningTime();
        lastCalculateStepCount = RunningPreferences.getInstance().getLastCalculateStepCount();
        if (runningState == PAUSE) {
            setState(RUNNING);//初始化一下数据，不可删
        }
        setState(runningState);
//        String runningActivity = RunningPreferences.getInstance().getRunningActivity();
//        Log.e(TAG, "restore state  runningActivity is " + runningActivity);
//        if (!TextUtils.isEmpty(runningActivity)) {//也可以在SplashActivity或MainActivity里面判断是否有跑步未结束 如果有或者直接启动界面
//            Intent intent = new Intent(runningActivity);
//            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//            if(RunningPreferences.getInstance().getBoolean(RunningPreferences.IS_PERSONAL_MARATHON)){
//                intent.putExtra(Constant.MARATHON_DISTANCE, RunningPreferences.getInstance().getString(Constant.MARATHON_DISTANCE));
//                intent.putExtra(Constant.MARATHON_TITLE, RunningPreferences.getInstance().getString(Constant.MARATHON_TITLE));
//                intent.putExtra(Constant.MARATHON_ID, RunningPreferences.getInstance().getString(Constant.MARATHON_ID));
//            }
//            startActivity(intent);
//        }
//        if(RunningPreferences.getInstance().getIsShowAddToWhiteListNotice()) {
//            showAddToWhiteListNotice();
//        }
    }

    private void initPedometer() {
        PedometerPresenter pedometerPresenter = new PedometerPresenter(this);
        pedometerPresenter.resume();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            if(ACTION_KEEP_ALIVE.equals(intent.getAction())){
                return START_STICKY;
            }
            String runningActivity = intent.getStringExtra(RUNNING_ACTIVITY);
            RunningPreferences.getInstance().setRunningActivity(runningActivity);
            mNeedExtraData = intent.getBooleanExtra(NEED_EXTRA_DATA, false);
            mNeedSaveRecord = intent.getBooleanExtra(NEED_SAVE_RECORD, false);
            mNeedSaveState = intent.getBooleanExtra(NEED_SAVE_STATE, false);
            mIsIndoorRunning = intent.getBooleanExtra(IS_INDOOR_RUNNING,false);
            mUserHeight = intent.getIntExtra(USER_HEIGHT,0);
            mUserWeight = intent.getFloatExtra(USER_WEIGHT,0);
            if(mUserWeight <= 0) mUserWeight = DEFAULT_WEIGHT;
            if(mUserHeight <= 0) mUserHeight = DEFAULT_HEIGHT;
            RunningPreferences.getInstance().putBoolean(IS_INDOOR_RUNNING,mIsIndoorRunning);
        }
        return START_STICKY;
    }

    private void showNotification() {
        String distanceStr = mDecimalFormat.format(runningDistance / 1000);
        Intent runningActivity = new Intent(RunningPreferences.getInstance().getRunningActivity());
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, runningActivity, PendingIntent.FLAG_UPDATE_CURRENT);
        Notification notification = new Notification.Builder(this)
                .setAutoCancel(true)
                .setContentTitle(getString(R.string.app_name))
                .setContentText("跑步正在进行中，您已经运动了" + distanceStr + "公里")
                .setContentIntent(contentIntent)
                .setSmallIcon(R.mipmap.ic_logo)
                .build();
        startForeground(1, notification); //设置为前台服务
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Logger.e(TAG+ "onBind");
//        mIsBound = true;
        //
        return new LocalBinder();
    }

    @Override
    public void onRebind(Intent intent) {
        Logger.e(TAG+ "onRebind");
        super.onRebind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Logger.e(TAG+ "onUnbind");
//        mIsBound = false ;
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Logger.e(TAG+ "onDestroy");
        releaseResource();
    }

    private void releaseResource() {
        if (!mIsResourceReleased) {
            if (mTimer != null) mTimer.cancel();
            stopForeground(true);
            if(!mIsIndoorRunning)destroyLocation();
            mIsResourceReleased = true;
            //  removeGpsListener
        }
    }

    @Override
    public void onLocationChanged(AMapLocation aMapLocation) {
        lastLocationCallbackTime = System.currentTimeMillis();
        if (aMapLocation != null && aMapLocation.getErrorCode() == AMapLocation.LOCATION_SUCCESS) {
//            if(!mIsBound){
//                return;
//            }

            if (aMapLocation.getAccuracy() < FILTER_THRESHOLD) {
                if (mRunningState == RUNNING) {
                    Double lat = aMapLocation.getLatitude();
                    Double lng = aMapLocation.getLongitude();
                    Double altitude = aMapLocation.getAltitude();
                    LatLng newLatLng = new LatLng(lat, lng);
                    Bundle bundle = new Bundle();
                    if (lastLatLng != null) {
                        float distanceIncrement = AMapUtils.calculateLineDistance(lastLatLng, newLatLng);
                        if (isDrift(distanceIncrement)){
                            return;
                        }
                        runningDistance += distanceIncrement;
                        if (mNeedSaveState) RunningPreferences.getInstance().setRunningDistance(runningDistance);
                        showNotification();
                    }
                    lastLatLng = newLatLng;
                    putDataToBundle(altitude, newLatLng, bundle);
                    if (mOnDataUpdateListener != null) {
                        mOnDataUpdateListener.onDataUpdated(bundle);
                    }
                    if (mNeedSaveRecord) {
                        saveToDatabase(bundle);
                    }
                    if(BuildConfig.DEBUG) Log.e("onLocationChanged", "current LatLng is " + newLatLng +"\nrunningDistance is "+runningDistance+"\naccuracy is " + aMapLocation.getAccuracy()
                            + "\nspeed is " + aMapLocation.getSpeed() + "\nprovider is " + aMapLocation.getProvider() + "object is " + this
                            + "\nstate is " + mRunningState);
                }
            } else {
                if(BuildConfig.DEBUG){
                    Log.e("onLocationChanged", "精度不够，过滤掉---》accuracy is " + aMapLocation.getAccuracy());
                    Toast.makeText(getApplicationContext(),"精度不够，过滤掉",Toast.LENGTH_SHORT).show();
                }
            }
        } else {
            if(BuildConfig.DEBUG)Toast.makeText(getApplicationContext(),"高德本次定位失败",Toast.LENGTH_SHORT).show();
            if (aMapLocation != null) {
                if(BuildConfig.DEBUG){
                    Log.e("onLocationChanged", "定位失败---》error code " + aMapLocation.getErrorCode() + "\n error info " + aMapLocation.getErrorInfo());
                }
            }
        }
    }

    /**
     * 该算法不完善有以下缺点待优化：
     * 1.漂移的情况和坐车等大于RUNNING_VELOCITY__LIMIT的移动的情况被同等处理了......即只要超过速度上限都被视为漂移点了。。。
     * 而且这样的话会造成停止超速移动后接着按常速移动后产生的点依然还是被判断为漂移点，因为算的是开始高速移动到现在的速度平均值，
     * 这个值只要大于RUNNING_VELOCITY__LIMIT值那么依然视作漂移，所以无法及时反映速度变化，从而造成滞后效应
     * 2.如果相邻两次回调之间的时间间隔很长（比如两次回调间夹杂了很多精度过低被过滤的点），比如第一个点正常然后接着都是精度过高被过滤，一直过了两分钟后才来一个精度合格的点，但该点是属于漂移点
     * 假设原地漂移了1000米那么计算的速度为1000/120=8.33 <HUMAN_RUNNING_VELOCITY_UPPER_LIMIT 所以依然被视为了正常点。。。
     * 3.getSpeed和isDrift里面的速度计算感觉重复了！
     * @param distanceIncrement
     * @return
     */
    private boolean isDrift(float distanceIncrement) {
        int timeDiff = getRunningTime() - lastCalculateRunningTime ;
        float velocity = 0;
        if(timeDiff >0){
            velocity = distanceIncrement/timeDiff ;
        }
        if(velocity > HUMAN_RUNNING_VELOCITY_UPPER_LIMIT){
            return true;
        }
        return false;
    }

    private void putDataToBundle(Double altitude, LatLng newLatLng, Bundle bundle) {
        int curRunningTime = getRunningTime();

        kmReport(newLatLng, bundle,curRunningTime);
        String pace = getPace(curRunningTime).replaceAll(":", "'") + "''";
        bundle.putFloat(DISTANCE, runningDistance);
        bundle.putString(CALORIE, getCalorie());
        bundle.putString(PACE, pace);
        bundle.putString(STEP, String.valueOf(stepCount));
        if (mNeedExtraData) {
            bundle.putParcelable(LAT_LNG, newLatLng);
            bundle.putString(FREQUENCY, getStepFrequency(curRunningTime));
            bundle.putString(STRIDE, getStride());
            bundle.putString(SPEED, getSpeed(curRunningTime));
            bundle.putString(ALTITUDE, String.valueOf(altitude));
        }

        lastCalculateDistance = runningDistance;
        lastCalculateRunningTime = curRunningTime;
        lastCalculateStepCount = stepCount;
        if(mNeedSaveState){
            RunningPreferences.getInstance().setRunningPace(pace);
            RunningPreferences.getInstance().setLastCalculateDistance(lastCalculateDistance);
            RunningPreferences.getInstance().setLastCalculateRunningTime(lastCalculateRunningTime);
            RunningPreferences.getInstance().setLastCalculateStepCount(lastCalculateStepCount);
        }
    }

    private void saveToDatabase(Bundle data) {
        RunningRecord record = new RunningRecord();
        record.setAltitude(data.getString(ALTITUDE));
        LatLng latLng = data.getParcelable(LAT_LNG);
        record.setLat(latLng.latitude);
        record.setLng(latLng.longitude);
        record.setFrequency(data.getString(FREQUENCY));
        record.setCalorie(data.getString(CALORIE));
        record.setPace(data.getString(PACE));
        record.setKmPace(data.getString(KM_PACE));
        record.setKmValue(data.getString(KM_VALUE));
        record.setStep(data.getString(STEP));
        record.setSpeed(data.getString(SPEED));
        record.setStride(data.getString(STRIDE));
        record.setDistance(String.valueOf(runningDistance));
        record.setTime(getRunningTime());
//        record.saveAsync().listen(new SaveCallback() {
//            @Override
//            public void onFinish(boolean isSuccess) {//该版本的Litepal有点问题，异步存储必须增加回调监听
//               if(BuildConfig.DEBUG) Log.e(TAG, " saveAsync--result is " + isSuccess);
//            }
//        });
        mRunningRecordBox.put(record);
        Logger.e("save data --"+ mRunningRecordBox.count());
    }

    public void clearDatabase() {
//        DataSupport.deleteAllAsync(RunningRecord.class).listen(new UpdateOrDeleteCallback() {
//            @Override
//            public void onFinish(int resultCode) {
//                if(BuildConfig.DEBUG) Log.e("clearDatabase", " affected rows " + resultCode);
//            }
//        });
        mRunningRecordBox.removeAll();
    }

    private void reset() {

    }


    private void initLocation() {
        AMapLocationClientOption locationOption = new AMapLocationClientOption();
        //关闭缓存机制
        //当开启定位缓存功能，在高精度模式和低功耗模式下进行的网络定位结果均会生成本地缓存，不区分单次定位还是连续定位。GPS定位结果不会被缓存。
        locationOption.setLocationCacheEnable(false);
        //设置是否强制刷新WIFI，默认为true，强制刷新。
        //每次定位主动刷新WIFI模块会提升WIFI定位精度，但相应的会多付出一些电量消耗。
        locationOption.setWifiActiveScan(false);
        // 设置定位模式为高精度模式
        //设置定位模式为High_Accuracy高精度模式，Battery_Saving为低功耗模式，Device_Sensors是仅设备模
        //高精度模式:会同时使用网络定位和GPS定位，优先返回最高精度的定位结果，以及对应的地址描述信息。
        //低功耗定位模式：不会使用GPS和其他传感器，只会使用网络定位（Wi-Fi和基站定位）；
        //仅用设备定位模式：不需要连接网络，只使用GPS进行定位，这种模式下不支持室内环境的定位，自 v2.9.0 版本支持返回地址描述信息。
        locationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
        //设置是否返回地址信息（默认返回地址信息）
        locationOption.setNeedAddress(false);
        //每秒定位一次
        locationOption.setInterval(LOCATION_INTERVAL);
        //设置是否允许模拟位置,默认为false，不允许模拟位置
        locationOption.setMockEnable(false);
        //设置是否定位一次
        locationOption.setOnceLocation(false);

        // 获取最近3s内精度最高的一次定位结果：
        // 设置setOnceLocationLatest(boolean
        // b)接口为true，启动定位时SDK会返回最近3s内精度最高的一次定位结果。如果设置其为true，setOnceLocation(boolean
        // b)接口也会被设置为true，反之不会，默认为false。
        locationOption.setOnceLocationLatest(false);

        mLocationClient = new AMapLocationClient(getApplicationContext());
        //设置定位监听
        mLocationClient.setLocationListener(this);
        // 设置定位参数
        mLocationClient.setLocationOption(locationOption);
    }

    private void startLocation() {
        Logger.e(TAG+"--startLocation");
        if (null != mLocationClient) {
            mLocationClient.startLocation();
        }
    }

    private void stopLocation() {
        if (null != mLocationClient) {
            mLocationClient.stopLocation();
        }
    }

    private void destroyLocation() {
        if (null != mLocationClient) {
            mLocationClient.unRegisterLocationListener(this);
            mLocationClient.onDestroy();
            mLocationClient = null;
        }
    }

    public void setState(int state) {
        Log.e("setState", "state is " + state);
        this.mRunningState = state;
        if (mNeedSaveState) {
            RunningPreferences.getInstance().setRunningState(state);
        }
        switch (mRunningState) {
            case RUNNING:
                showNotification();
                runningStartTime = System.currentTimeMillis();
                if(!mIsIndoorRunning) startLocation();
                ApplicationModule.getInstance().getPedometerManager().startPedometerService();
                stepIncrement = 0;
                if (mTimer != null && !mIsTimerSet) {
                    mTimer.schedule(new TimingTask(), 1000, 1000);
                    mIsTimerSet = true;
                }
                if(!mIsKeepAliveStarted){
                    startKeepAlive();
                    mIsKeepAliveStarted = true;
                }
                break;
            case PAUSE:
                if(!mIsIndoorRunning) stopLocation();
                ApplicationModule.getInstance().getPedometerManager().stopPedometerService();
                runningTimeSum += System.currentTimeMillis() - runningStartTime;
                stepCountSum += stepIncrement;
                lastLatLng = null;//暂停期间的距离不能算入总距离
                lastLocationCallbackTime = 0;
                break;
            case FINISH:
                ApplicationModule.getInstance().getPedometerManager().stopPedometerService();
                releaseResource();
                RunningPreferences.getInstance().clear();
                clearDatabase();  //如果担心清除数据库数据失败可以在跑步界面里面按开始跑步时（倒数三秒后）执行一次数据库清理（这样每次进入跑步界面开始新的跑步前就把上次的清空了）
                stopKeepAlive();
                stopSelf();//也可以服务始终开启，跑步Activity只绑定和解绑，结束就清空Preference数据，并复位各变量
                break;
        }
    }

    public int getRunningState() {
        return mRunningState;
    }

    public boolean hasOngoingRunning() {
        return mRunningState == RUNNING || mRunningState == PAUSE;
    }

    /**
     * 返回跑步时间 单位秒
     * @return
     */

    private int getRunningTime() {
        long now = System.currentTimeMillis();
        long runningTime;
        int result;
        if (PAUSE == mRunningState) {
            runningTime = runningTimeSum;
        } else {
            runningTime = now - runningStartTime + runningTimeSum;
        }
        result = (int) (runningTime / 1000);
        if (mNeedSaveState) RunningPreferences.getInstance().setRunningTime(result);
        return result;
    }

    /**
     * 计算平均配速
     * @return
     */
    private String getAvgPace() {
        int paceSec = 0;
        float kmDistance = Float.parseFloat(mDecimalFormat.format(runningDistance / 1000));
        if (kmDistance > 0) {
            paceSec = (int) (getRunningTime() / kmDistance);
        }
        return RunningUtils.getMsTime(paceSec);
    }

    private String getPace(int curRunningTime){
        int paceSec = 0;
        float disDiff = Float.parseFloat(mDecimalFormat.format((runningDistance - lastCalculateDistance) / 1000));
//        int curRunningTime = getRunningTime();
        int timeDiff = curRunningTime - lastCalculateRunningTime;
        if(disDiff >0 ){
            paceSec =(int)(timeDiff/disDiff) ;
        }
//        lastCalculateDistance = runningDistance;
//        lastCalculateRunningTime = curRunningTime;
//        if(mNeedSaveState) RunningPreferences.getInstance().setLastCalculateDistance(lastCalculateDistance);
//        if(mNeedSaveState) RunningPreferences.getInstance().setLastCalculateRunningTime(lastCalculateRunningTime);
//        Log.e(TAG,"getPace time diff is "+timeDiff+"\n distance diff is "+disDiff);
//        Log.e(TAG,"getPace pace is "+ RunningUtils.getMsTime(paceSec));
        return RunningUtils.getMsTime(paceSec);
    }

    /**
     * 整公里播报，同时获取整公里点和记录整公里配速
     *
     * @param newLatLng
     * @param bundle
     */
    private void kmReport(LatLng newLatLng, Bundle bundle,int curRunningTime) {
        int curDistance = (int) runningDistance / 1000;
        if (curDistance - lastKmDistance >= 1) {
            int kmPace = curRunningTime - lastKmRunningTime;//获取整公里配速--因为整公里配速不展示只用于上传，所以不用转换格式
            if (kmPace < 0) kmPace = 0;
            bundle.putParcelable(KM_LAT_LNG, newLatLng);
            bundle.putString(KM_PACE, String.valueOf(kmPace));
            bundle.putString(KM_VALUE, String.valueOf(curDistance));//本来不需要这个，但是前端需要。。。
            lastKmDistance = curDistance;
            lastKmRunningTime = curRunningTime;
            if (mNeedSaveState) {
                RunningPreferences.getInstance().setLastKmDistance(lastKmDistance);
                RunningPreferences.getInstance().setLastKmRunningTime(lastKmRunningTime);
            }
            SpeechUtil.getInstance().speak("您已经跑了" + curDistance + "公里，用时"+RunningUtils.getReportTimeStr(curRunningTime)+
                    "最近一公里用时为" + RunningUtils.getReportTimeStr(kmPace));
        }
    }


    /**
     * 获取步频
     * 步/分钟
     */
    private String getStepFrequency(int curRunningTime) {
        int steps = stepCount - lastCalculateStepCount;
        int result = 0;
        if (curRunningTime - lastCalculateRunningTime > 0) {
            float timeDiff = (curRunningTime -lastCalculateRunningTime)/60f;
            if(timeDiff>0) result =(int) (steps / timeDiff) ;
        }
        return String.valueOf(result);
    }


    /**
     * 获取步幅
     * 米/步
     */
    private String getStride() {
        float dis = (runningDistance - lastCalculateDistance);
        int steps = stepCount - lastCalculateStepCount;
        if (steps > 0) {
            return String.valueOf(dis / (float) steps);
        }
        return "0";
    }

    /**
     * 获取速度
     * m/s
     */
//    private float lastSpeedDistance;
//    private int lastSpeedRunningTime;
    private String getSpeed(int curRunningTime) {
        float disDiff = runningDistance - lastCalculateDistance;
//        int curRunningTime = getRunningTime();
        int timeDiff = curRunningTime - lastCalculateRunningTime;
        float velocity = 0;
        if(timeDiff >0 ){
            velocity = disDiff /timeDiff;
        }
//        lastSpeedDistance = runningDistance;
//        lastSpeedRunningTime = curRunningTime;
//        Log.e(TAG,"getSpeed dis diff is "+disDiff+"\n time diff is "+timeDiff);
//        Log.e(TAG,"getSpeed speed is "+mDecimalFormat.format(velocity));
        return mDecimalFormat.format(velocity) ;
    }

    /**
     * 计算卡路里
     * 体重（kg）×距离（公里）×1.036
     */
    private String getCalorie() {
        String calories;
//        int weight;
//        try {
//            Float userWeight = UserPreferences.getInstance().getFloat(UserPreferences.USER_WEIGHT);
//            weight = userWeight.intValue();
//            if(weight <= 0){
//                weight = DEFAULT_WEIGHT;
//            }
//        } catch (Exception e) {
//            weight = DEFAULT_WEIGHT;
//        }
        calories = String.valueOf((int) (((runningDistance / 1000) * mUserWeight) * 1.036));
        if (mNeedSaveState) RunningPreferences.getInstance().setRunningCalorie(calories);
        return calories;
    }

    private float getIndoorRunningDistanceIncrement(int curRunningTime){
        float result;
        int stepIncrement = stepCount - lastCalculateStepCount;
        result = stepIncrement * getIndoorRunningStride(curRunningTime);
        return result;
    }

    private float getIndoorRunningStride(int curRunningTime){//单位 米
        float stride ,k;
        int stepFrequency = Integer.parseInt(getStepFrequency(curRunningTime));
        if(stepFrequency <= 130){
            k = 0.47f;
        }else if(stepFrequency > 130 && stepFrequency <=170) {
            k = 0.55f;
        }else {
            k = 0.65f;
        }
        stride = mUserHeight/100f * k;
        return  stride;
    }

    @Override
    public void onReaderPedometer(PedometerCardEntity cardEntity) {
        if (cardEntity != null) {
            Log.e(TAG, "incoming step  is " + cardEntity.getStepCount());
//            stepCount = lastStepCount + cardEntity.getStepCount();
            stepIncrement = cardEntity.getStepCount();
            stepCount = stepCountSum + cardEntity.getStepCount();
//            Log.e(TAG, "onReaderPedometer step count is " + stepCount);
            if (mNeedSaveState) RunningPreferences.getInstance().setRunningStep(stepCount);
        }
    }


    public class LocalBinder extends Binder {

        public RunningService getService() {
            return RunningService.this;
        }
    }

    private class TimingTask extends TimerTask {

        @Override
        public void run() {
            if (mOnDataUpdateListener != null) {
//                if(! mIsBound){
//                    return;
//                }
                if (mRunningState == RUNNING) {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            int runningTime = getRunningTime();
                            mOnDataUpdateListener.onRunningTime(runningTime);
                            if(mIsIndoorRunning){
                                handleIndoorRunning(runningTime);
                            }
                        }
                    });
                   if(!mIsIndoorRunning) pullUpAMapLocation();
                }
//                Log.e("TimingTask", "onRunningTime");
            }
        }
    }

    private void handleIndoorRunning(int runningTime) {
        if(runningTime % 5 == 0){
            float distanceIncrement = getIndoorRunningDistanceIncrement(runningTime);
            if(distanceIncrement == 0){
                return;
            }
            runningDistance += distanceIncrement ;
            if (mNeedSaveState) RunningPreferences.getInstance().setRunningDistance(runningDistance);
            showNotification();
            Bundle bundle = new Bundle();
            putDataToBundle(0d,new LatLng(0,0),bundle);//这里经纬度没用null 是避免saveToDatabase中data.getParcelable(LAT_LNG) 抛异常
            mOnDataUpdateListener.onDataUpdated(bundle);
            if(mNeedSaveRecord) saveToDatabase(bundle);
        }
    }

    private void pullUpAMapLocation() {
        if(lastLocationCallbackTime>0){
            if((System.currentTimeMillis() - lastLocationCallbackTime )> MAX_LOCATION_CALLBACK_INTERVAL){ //说明高德定位服务出现异常  进行拉活
                lastLocationCallbackTime = 0;
                destroyLocation();
                initLocation();
                startLocation();
            }
        }
    }


    public void registerOnDataUpdatedListener(OnDataUpdatedListener listener) {
        this.mOnDataUpdateListener = listener;
    }

    public void unRegisterOnDataUpdatedListener() {
        this.mOnDataUpdateListener = null;
    }

    public interface OnDataUpdatedListener {

        void onDataUpdated(Bundle data);

        void onRunningTime(int runningTime);

    }




    private boolean mIsKeepAliveStarted = false;

    /**
     * 添加重复唤醒任务，用于不停唤起服务
     */
    private void startKeepAlive() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            JobInfo.Builder builder = new JobInfo.Builder(KeepAliveService.JOB_KEEP_ALIVE, new ComponentName(getApplication(), KeepAliveService.class));
            builder.setPeriodic(KEEP_ALIVE_INTERVAL);
            builder.setPersisted(true);
            JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
            jobScheduler.schedule(builder.build());
        }else {
            PendingIntent pendingIntent = PendingIntent.getService(this, 0, getKeepAliveIntent(this), PendingIntent.FLAG_UPDATE_CURRENT);
            AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
            alarmManager.cancel(pendingIntent);
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + KEEP_ALIVE_INTERVAL, KEEP_ALIVE_INTERVAL, pendingIntent);
        }

    }

    private void stopKeepAlive(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
            jobScheduler.cancel(KeepAliveService.JOB_KEEP_ALIVE);
        }else {
            PendingIntent pendingIntent = PendingIntent.getService(this, 0, getKeepAliveIntent(this), PendingIntent.FLAG_UPDATE_CURRENT);
            AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
            alarmManager.cancel(pendingIntent);
        }
    }

    public static Intent getKeepAliveIntent(Context context) {
        return getActionIntent(context, ACTION_KEEP_ALIVE);
    }

    private static Intent getActionIntent(Context context, String action) {
        Intent intent = new Intent(context, RunningService.class);
        intent.setAction(action);
        return intent;
    }

}
